home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / javax / swing / ToolTipManager.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  23.4 KB  |  781 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)ToolTipManager.java    1.35 98/08/26
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15.  
  16. package javax.swing;
  17.  
  18. import java.awt.event.*;
  19. import java.applet.*;
  20. import java.awt.*;
  21.  
  22. /**
  23.  * Manages all the ToolTips in the system.
  24.  *
  25.  * @see JComponent#createToolTip
  26.  * @version 1.35 08/26/98
  27.  * @author Dave Moore
  28.  * @author Rich Schiavi
  29.  */
  30. public class ToolTipManager extends MouseAdapter implements MouseMotionListener  {
  31.     Timer enterTimer, exitTimer, insideTimer;
  32.     String toolTipText;
  33.     Point  preferredLocation;
  34.     JComponent insideComponent;
  35.     MouseEvent mouseEvent;
  36.     boolean showImmediately;
  37.     final static ToolTipManager sharedInstance = new ToolTipManager();
  38.     Popup tipWindow;
  39.     JToolTip tip;
  40.  
  41.     private Rectangle popupRect = null;
  42.     private Rectangle popupFrameRect = null;
  43.  
  44.     boolean enabled = true;
  45.     boolean mouseAboveToolTip = false;
  46.     private boolean tipShowing = false;
  47.     private long timerEnter = 0;
  48.    
  49.     private KeyStroke postTip,hideTip;
  50.     private AbstractAction postTipAction, hideTipAction;
  51.  
  52.     private FocusListener focusChangeListener = null;
  53.  
  54.     protected boolean lightWeightPopupEnabled = true;
  55.     protected boolean heavyWeightPopupEnabled = false;
  56.  
  57.     ToolTipManager() {
  58.         enterTimer = new Timer(750, new insideTimerAction());
  59.         enterTimer.setRepeats(false);
  60.         exitTimer = new Timer(500, new outsideTimerAction());
  61.         exitTimer.setRepeats(false);
  62.         insideTimer = new Timer(4000, new stillInsideTimerAction());
  63.         insideTimer.setRepeats(false);
  64.  
  65.     // create accessibility actions 
  66.     postTip = KeyStroke.getKeyStroke(KeyEvent.VK_F1,Event.CTRL_MASK);
  67.     postTipAction = new AbstractAction(){
  68.       public void actionPerformed(ActionEvent e){
  69.         if (tipWindow != null) // showing we unshow
  70.           hideTipWindow();
  71.         else {
  72.           hideTipWindow(); // be safe
  73.           enterTimer.stop();
  74.           exitTimer.stop();
  75.           insideTimer.stop();
  76.           insideComponent = (JComponent)e.getSource();
  77.           toolTipText = insideComponent.getToolTipText();
  78.           preferredLocation = new Point(10,insideComponent.getHeight()+10);  // manual set
  79.           showTipWindow();
  80.           // put a focuschange listener on to bring the tip down
  81.           if (focusChangeListener == null){
  82.         focusChangeListener = createFocusChangeListener();
  83.           }
  84.           insideComponent.addFocusListener(focusChangeListener); 
  85.         }
  86.       }
  87.       public boolean isEnabled(){
  88.         return true;
  89.       }
  90.     };
  91.     hideTip = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0);
  92.     hideTipAction = new AbstractAction(){
  93.       public void actionPerformed(ActionEvent e){
  94.         hideTipWindow();
  95.         JComponent jc = (JComponent)e.getSource();
  96.         jc.removeFocusListener(focusChangeListener);
  97.         preferredLocation = null;
  98.       }
  99.       public boolean isEnabled(){
  100.         return true;
  101.       }
  102.     };
  103.     }
  104.  
  105.     /**
  106.      * Enables or disables the tooltip.
  107.      *
  108.      * @param flag  true to enable the tip
  109.      */
  110.     public void setEnabled(boolean flag) {
  111.         enabled = flag;
  112.         if (!flag) {
  113.             hideTipWindow();
  114.         }
  115.     }
  116.  
  117.     /**
  118.      * Returns true if this object is enabled.
  119.      *
  120.      * @return true if this object is enabled
  121.      */
  122.     public boolean isEnabled() {
  123.         return enabled;
  124.     }
  125.  
  126.     /**
  127.      * When displaying the JToolTip, the ToolTipManager choose to use a light weight JPanel if
  128.      * it fits. This method allows you to disable this feature. You have to do disable
  129.      * it if your application mixes light weight and heavy weights components.
  130.      * @deprecated As of Swing1.1
  131.      *  replaced by <code>setToolTipWindowUsePolicy(int)</code>.
  132.      */
  133.     public void setLightWeightPopupEnabled(boolean aFlag){
  134.       lightWeightPopupEnabled = aFlag;
  135.     }
  136.     
  137.     /**
  138.      * Returns true if lightweight (all-Java) Tooltips are in use,
  139.      * or false if heavyweight (native peer) Tooltips are being used.
  140.      *
  141.      * @return true if lightweight ToolTips are in use
  142.      */
  143.     public boolean isLightWeightPopupEnabled() { 
  144.         return lightWeightPopupEnabled;
  145.     }
  146.  
  147.  
  148.     /**
  149.      * Specifies the initial delay value.
  150.      *
  151.      * @param microSeconds  an int specifying the number of microseconds
  152.      *        to delay (after the cursor has paused) before displaying the
  153.      *        tooltip
  154.      * @see #getInitialDelay
  155.      */
  156.     public void setInitialDelay(int microSeconds) {
  157.         enterTimer.setInitialDelay(microSeconds);
  158.     }
  159.  
  160.     /**
  161.      * Returns the initial delay value.
  162.      *
  163.      * @return an int representing the initial delay value
  164.      * @see #setInitialDelay
  165.      */
  166.     public int getInitialDelay() {
  167.         return enterTimer.getInitialDelay();
  168.     }
  169.  
  170.     /**
  171.      * Specifies the dismisal delay value.
  172.      *
  173.      * @param microSeconds  an int specifying the number of microseconds
  174.      *        to delay (after the cursor has moved on) before taking away
  175.      *        the tooltip
  176.      * @see #getDismissDelay
  177.      */
  178.     public void setDismissDelay(int microSeconds) {
  179.         insideTimer.setInitialDelay(microSeconds);
  180.     }
  181.  
  182.     /**
  183.      * Returns the dismisal delay value.
  184.      *
  185.      * @return an int representing the dismisal delay value
  186.      * @see #setDismissDelay
  187.      */
  188.     public int getDismissDelay() {
  189.         return insideTimer.getInitialDelay();
  190.     }
  191.  
  192.     /**
  193.      * Specifies the time to delay before reshowing the tooltip.
  194.      *
  195.      * @param microSeconds  an int specifying the time in microseconds
  196.      *        before reshowing the tooltip if the cursor stops again
  197.      * @see #getReshowDelay
  198.      */
  199.     public void setReshowDelay(int microSeconds) {
  200.         exitTimer.setInitialDelay(microSeconds);
  201.     }
  202.  
  203.     /**
  204.      * Returns the reshow delay value.
  205.      *
  206.      * @return an int representing the reshow delay value
  207.      * @see #setReshowDelay
  208.      */
  209.     public int getReshowDelay() {
  210.         return exitTimer.getInitialDelay();
  211.     }
  212.  
  213.     void showTipWindow() {
  214.         if(insideComponent == null || !insideComponent.isShowing())
  215.             return;
  216.         if (enabled) {
  217.             Dimension size;
  218.             Point screenLocation = insideComponent.getLocationOnScreen();
  219.             Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
  220.             Point location = new Point();
  221.  
  222.             // Just to be paranoid
  223.             hideTipWindow();
  224.  
  225.             tip = insideComponent.createToolTip();
  226.             tip.setTipText(toolTipText);
  227.             size = tip.getPreferredSize();
  228.  
  229.         // fix bug 4135787: Tooltips don't work when used in awt.Frame or awt.Applet, etc
  230.         // this is a quick and dirty check 
  231.         if (insideComponent.getRootPane() == null){
  232.           tipWindow = new WindowPopup((frameForComponent(insideComponent)),tip,size);
  233.           heavyWeightPopupEnabled = true;
  234.         }
  235.         else if (lightWeightPopupEnabled){
  236.           heavyWeightPopupEnabled = false;
  237.           tipWindow = new JPanelPopup(tip,size);
  238.         }
  239.         else {
  240.           heavyWeightPopupEnabled = false;
  241.           tipWindow = new PanelPopup(tip,size);
  242.         }
  243.  
  244.             tipWindow.addMouseListener(this);
  245.  
  246.             if(preferredLocation != null) {
  247.                 location.x = screenLocation.x + preferredLocation.x;
  248.                 location.y = screenLocation.y + preferredLocation.y;
  249.             } else {
  250.                 location.x = screenLocation.x + mouseEvent.getX();
  251.                 location.y = screenLocation.y + mouseEvent.getY() + 20;
  252.  
  253.                 if (location.x + size.width > screenSize.width) {
  254.                     location.x -= size.width;
  255.                 }
  256.                 if (location.y + size.height > screenSize.height) {
  257.                     location.y -= (size.height + 20);
  258.                 }
  259.             }
  260.  
  261.         // we do not adjust x/y when using awt.Window tips
  262.         if (!heavyWeightPopupEnabled){
  263.  
  264.         if (popupRect == null){
  265.           popupRect = new Rectangle();
  266.         }
  267.         popupRect.setBounds(location.x,location.y,
  268.                     tipWindow.getBounds().width,tipWindow.getBounds().height);
  269.  
  270.         int y = getPopupFitHeight(popupRect, insideComponent);
  271.         int x = getPopupFitWidth(popupRect,insideComponent);
  272.  
  273.         if (y > 0){
  274.             location.y -= y;
  275.         }
  276.         if (x > 0){
  277.             // adjust
  278.             location.x -= x;
  279.         }
  280.         }        
  281.  
  282.         tipWindow.show(insideComponent,location.x,location.y);
  283.             insideTimer.start();
  284.         timerEnter = System.currentTimeMillis();
  285.         tipShowing = true;
  286.         }
  287.     }
  288.  
  289.     void hideTipWindow() {
  290.         if (tipWindow != null) {
  291.             tipWindow.removeMouseListener(this);
  292.         tipWindow.hide();
  293.         tipWindow = null;
  294.         tipShowing = false;
  295.         timerEnter = 0;
  296.         (tip.getUI()).uninstallUI(tip);
  297.             tip = null;
  298.             insideTimer.stop();
  299.         }
  300.     }
  301.  
  302.     /**
  303.      * Returns a shared ToolTipManager instance.
  304.      *
  305.      * @return a shared ToolTipManager object
  306.      */
  307.     public static ToolTipManager sharedInstance() {
  308.         return sharedInstance;
  309.     }
  310.  
  311.     // add keylistener here to trigger tip for access
  312.     /**
  313.      * Register a component for tooltip management.
  314.      *
  315.      * @param component  a JComponent object
  316.      */
  317.     public void registerComponent(JComponent component) {
  318.         component.removeMouseListener(this);
  319.         component.addMouseListener(this);
  320.     // register our accessibility keybindings for this component
  321.     // this will apply globally across L&F
  322.     // Post Tip: Ctrl+F1
  323.     // Unpost Tip: Esc and Ctrl+F1
  324.     component.registerKeyboardAction(postTipAction,postTip,JComponent.WHEN_FOCUSED);
  325.     component.registerKeyboardAction(hideTipAction,hideTip,JComponent.WHEN_FOCUSED);
  326.     }
  327.  
  328.     /**
  329.      * Remove a component from tooltip control.
  330.      *
  331.      * @param component  a JComponent object
  332.      */
  333.     public void unregisterComponent(JComponent component) {
  334.         component.removeMouseListener(this);
  335.     component.unregisterKeyboardAction(postTip);
  336.     component.unregisterKeyboardAction(hideTip);
  337.     }
  338.  
  339.  
  340.     // implements java.awt.event.MouseListener
  341.     public void mouseEntered(MouseEvent event) {
  342.        // this is here for a workaround for a Solaris *application* only bug
  343.        // in which an extra MouseExit/Enter events are generated when a Panel
  344.        // initially is shown
  345.       if ((tipShowing) && !lightWeightPopupEnabled)
  346.     {
  347.         if (System.currentTimeMillis() - timerEnter < 200){
  348.         return;
  349.         }
  350.     }  
  351.         if(event.getSource() == tipWindow)
  352.             return;
  353.  
  354.         JComponent component = (JComponent)event.getSource();
  355.         toolTipText = component.getToolTipText(event);
  356.         preferredLocation = component.getToolTipLocation(event);
  357.  
  358.         exitTimer.stop();
  359.  
  360.     Point location = event.getPoint();
  361.     // ensure tooltip shows only in proper place
  362.     if (location.x < 0 || 
  363.         location.x >=component.getWidth() ||
  364.         location.y < 0 ||
  365.         location.y >= component.getHeight())
  366.       {
  367.         return;
  368.       }
  369.  
  370.         if (insideComponent != null) {
  371.             enterTimer.stop();
  372.             insideComponent = null;
  373.         }
  374.  
  375.         component.addMouseMotionListener(this);
  376.  
  377.         insideComponent = component;
  378.     //        if (toolTipText != null) {
  379.     // fix for 4133318
  380.     if (tipWindow != null){
  381.       // fix for 4139679
  382.       // without this - the tip flashes
  383.       // since we get extra enter from the
  384.       // tip window when being displayed over top
  385.       // of the component - the behaviour is
  386.       // the same whether or not we are over the
  387.       // component - so additional location checks unneeded
  388.       if (heavyWeightPopupEnabled){ 
  389.         return;
  390.       }
  391.       else {
  392.         mouseEvent = event;
  393.             if (showImmediately) {
  394.           showTipWindow();
  395.             } else {
  396.           enterTimer.start();
  397.             }
  398.       }
  399.         }
  400.     }
  401.  
  402.     // implements java.awt.event.MouseListener
  403.     public void mouseExited(MouseEvent event) {
  404.        // this is here for a workaround for a Solaris *application* only bug
  405.       //  when Panels are used
  406.       if ((tipShowing) && !lightWeightPopupEnabled)
  407.     {
  408.         if (System.currentTimeMillis() - timerEnter < 200)
  409.         {
  410.         return;
  411.         }
  412.     }  
  413.  
  414.         boolean shouldHide = true;
  415.         if (insideComponent == null) {
  416.             // Drag exit
  417.         } 
  418.         if(event.getSource() == tipWindow) {
  419.       // if we get an exit and have a heavy window
  420.       // we need to check if it if overlapping the inside component
  421.             Container insideComponentWindow = insideComponent.getTopLevelAncestor();
  422.             Rectangle b = tipWindow.getBounds();
  423.             Point location = event.getPoint();
  424.             location.x += b.x;
  425.             location.y += b.y;
  426.  
  427.             b = insideComponentWindow.getBounds();
  428.             location.x -= b.x;
  429.             location.y -= b.y;
  430.             
  431.             location = SwingUtilities.convertPoint(null,location,insideComponent);
  432.             if(location.x >= 0 && location.x < insideComponent.getWidth() &&
  433.                location.y >= 0 && location.y < insideComponent.getHeight()) {
  434.                 shouldHide = false;
  435.             } else
  436.           shouldHide = true;
  437.         } else if(event.getSource() == insideComponent && tipWindow != null) {
  438.             Point location = SwingUtilities.convertPoint(insideComponent,
  439.                                                          event.getPoint(),
  440.                                                          null);
  441.             Rectangle bounds = insideComponent.getTopLevelAncestor().getBounds();
  442.             location.x += bounds.x;
  443.             location.y += bounds.y;
  444.  
  445.             bounds = tipWindow.getBounds();
  446.             if(location.x >= bounds.x && location.x < (bounds.x + bounds.width) &&
  447.                location.y >= bounds.y && location.y < (bounds.y + bounds.height)) {
  448.                 shouldHide = false;
  449.             } else
  450.                 shouldHide = true;
  451.         } 
  452.         
  453.         if(shouldHide) {        
  454.             enterTimer.stop();
  455.         if (insideComponent != null) {
  456.           insideComponent.removeMouseMotionListener(this);
  457.         }
  458.             insideComponent = null;
  459.             toolTipText = null;
  460.             mouseEvent = null;
  461.             hideTipWindow();
  462.             exitTimer.start();
  463.         }
  464.     }
  465.  
  466.     // implements java.awt.event.MouseListener
  467.     public void mousePressed(MouseEvent event) {
  468.         hideTipWindow();
  469.         enterTimer.stop();
  470.         showImmediately = false;
  471.     }
  472.  
  473.     // implements java.awt.event.MouseMotionListener
  474.     public void mouseDragged(MouseEvent event) {
  475.     }
  476.  
  477.     // implements java.awt.event.MouseMotionListener
  478.     public void mouseMoved(MouseEvent event) {
  479.         JComponent component = (JComponent)event.getSource();
  480.         String newText = component.getToolTipText(event);
  481.         Point  newPreferredLocation = component.getToolTipLocation(event);
  482.  
  483.         if (newText != null || newPreferredLocation != null) {
  484.             mouseEvent = event;
  485.             if (((newText != null && newText.equals(toolTipText)) || newText == null) &&
  486.                 ((newPreferredLocation != null && newPreferredLocation.equals(preferredLocation)) 
  487.                  || newPreferredLocation == null)) {
  488.                 if (tipWindow != null) {
  489.                     insideTimer.restart();
  490.                 } else {
  491.                     enterTimer.restart();
  492.                 }
  493.             } else {
  494.                 toolTipText = newText;
  495.                 preferredLocation = newPreferredLocation;
  496.                 if (showImmediately) {
  497.                     hideTipWindow();
  498.                     showTipWindow();
  499.                 } else {
  500.                     enterTimer.restart();
  501.                 }
  502.             }
  503.         } else {
  504.             toolTipText = null;
  505.             preferredLocation = null;
  506.             mouseEvent = null;
  507.             hideTipWindow();
  508.             enterTimer.stop();
  509.             exitTimer.start();
  510.         }
  511.     }
  512.  
  513.     protected class insideTimerAction implements ActionListener {
  514.         public void actionPerformed(ActionEvent e) {
  515.             if(insideComponent != null && insideComponent.isShowing()) {
  516.                 showImmediately = true;
  517.                 showTipWindow();
  518.             }
  519.         }
  520.     }
  521.  
  522.     protected class outsideTimerAction implements ActionListener {
  523.         public void actionPerformed(ActionEvent e) {
  524.             showImmediately = false;
  525.         }
  526.     }
  527.  
  528.     protected class stillInsideTimerAction implements ActionListener {
  529.         public void actionPerformed(ActionEvent e) {
  530.             hideTipWindow();
  531.             enterTimer.stop();
  532.             showImmediately = false;
  533.         }
  534.     }
  535.  
  536.     static Frame frameForComponent(Component component) {
  537.         while (!(component instanceof Frame)) {
  538.             component = component.getParent();
  539.         }
  540.         return (Frame)component;
  541.     }
  542.  
  543.   private FocusListener createFocusChangeListener(){
  544.     return new FocusAdapter(){
  545.       public void focusLost(FocusEvent evt){
  546.     hideTipWindow();
  547.     JComponent c = (JComponent)evt.getSource();
  548.     c.removeFocusListener(focusChangeListener);
  549.       }
  550.     };
  551.   }
  552.  
  553.   // Returns: 0 no adjust
  554.   //         -1 can't fit
  555.   //         >0 adjust value by amount returned
  556.   private int getPopupFitWidth(Rectangle popupRectInScreen, Component invoker){
  557.     if (invoker != null){
  558.       Container parent;
  559.       for (parent = invoker.getParent(); parent != null; parent = parent.getParent()){
  560.     // fix internal frame size bug: 4139087 - 4159012
  561.     if(parent instanceof JFrame || parent instanceof JDialog ||
  562.        parent instanceof JWindow) { // no check for awt.Frame since we use Heavy tips
  563.       return getWidthAdjust(parent.getBounds(),popupRectInScreen);
  564.     } else if (parent instanceof JApplet || parent instanceof JInternalFrame) {
  565.       if (popupFrameRect == null){
  566.         popupFrameRect = new Rectangle();
  567.       }
  568.       Point p = parent.getLocationOnScreen();
  569.       popupFrameRect.setBounds(p.x,p.y,
  570.                    parent.getBounds().width,
  571.                    parent.getBounds().height);
  572.       return getWidthAdjust(popupFrameRect,popupRectInScreen);
  573.     }
  574.       }
  575.     }
  576.     return 0;
  577.   }
  578.  
  579.   // Returns:  0 no adjust
  580.   //          >0 adjust by value return
  581.   private int getPopupFitHeight(Rectangle popupRectInScreen, Component invoker){
  582.     if (invoker != null){
  583.       Container parent;
  584.       for (parent = invoker.getParent(); parent != null; parent = parent.getParent()){
  585.     if(parent instanceof JFrame || parent instanceof JDialog ||
  586.        parent instanceof JWindow) {
  587.       return getHeightAdjust(parent.getBounds(),popupRectInScreen);
  588.     } else if (parent instanceof JApplet || parent instanceof JInternalFrame) {
  589.       if (popupFrameRect == null){
  590.         popupFrameRect = new Rectangle();
  591.       }
  592.       Point p = parent.getLocationOnScreen();
  593.       popupFrameRect.setBounds(p.x,p.y,
  594.                    parent.getBounds().width,
  595.                    parent.getBounds().height);
  596.       return getHeightAdjust(popupFrameRect,popupRectInScreen);
  597.     }
  598.       }
  599.     }
  600.     return 0;
  601.   }
  602.  
  603.   private int getHeightAdjust(Rectangle a, Rectangle b){
  604.     if (b.y >= a.y && (b.y + b.height) <= (a.y + a.height))
  605.       return 0;
  606.     else
  607.       return (((b.y + b.height) - (a.y + a.height)) + 5);
  608.   }
  609.  
  610.   // Return the number of pixels over the edge we are extending.
  611.   // If we are over the edge the ToolTipManager can adjust.
  612.   // REMIND: what if the Tooltip is just too big to fit at all - we currently will just clip
  613.   private int getWidthAdjust(Rectangle a, Rectangle b){
  614.     //    System.out.println("width b.x/b.width: " + b.x + "/" + b.width +
  615.     //               "a.x/a.width: " + a.x + "/" + a.width);
  616.     if (b.x >= a.x && (b.x + b.width) <= (a.x + a.width)){
  617.       return 0;
  618.     }
  619.     else {
  620.       return (((b.x + b.width) - (a.x +a.width)) + 5);
  621.     }
  622.   }
  623.     
  624.   /*
  625.    * The following interface describes what a popup should implement.
  626.    * We do this because the ToolTip manager uses popup that can be windows or
  627.    * panels. The reason is two-fold: We'd like to use panels mostly, but when the
  628.    * panel (or tooltip) would not fit, we need to use a Window to avoid the panel
  629.    * being clipped or not shown.
  630.    *
  631.    */
  632.   private interface Popup {
  633.     public void show(JComponent invoker, int x, int y);
  634.     public void hide();
  635.     public void addMouseListener(ToolTipManager c);
  636.     public void removeMouseListener(ToolTipManager c);
  637.     public Rectangle getBounds();
  638.   }
  639.  
  640.  
  641.   class JPanelPopup extends JPanel implements Popup  {
  642.     public JPanelPopup(JComponent t, Dimension s) {
  643.       super();
  644.       setLayout(new BorderLayout());
  645.       setDoubleBuffered(true);
  646.       this.setOpaque(true);
  647.       add(t, BorderLayout.CENTER);
  648.       setSize(s);
  649.     }
  650.  
  651.     public void update(Graphics g) {
  652.       paint(g);
  653.     }
  654.         
  655.     public Rectangle getBounds(){
  656.     return super.getBounds();
  657.     }
  658.  
  659.  
  660.     public void show(JComponent invoker, int x, int y) {
  661.       Point p = new Point(x,y);
  662.       SwingUtilities.convertPointFromScreen(p,invoker.getRootPane().getLayeredPane());
  663.       this.setBounds(p.x,p.y,getSize().width, getSize().height);
  664.       invoker.getRootPane().getLayeredPane().add(this,JLayeredPane.POPUP_LAYER,0);
  665.     }
  666.  
  667.     public void hide() {
  668.       Container parent = getParent();
  669.       Rectangle r = this.getBounds();
  670.       if(parent != null){
  671.     parent.remove(this);
  672.     parent.repaint(r.x,r.y,r.width,r.height);
  673.       }
  674.     }
  675.  
  676.     public void addMouseListener(ToolTipManager c){
  677.     super.addMouseListener(c);
  678.     }
  679.  
  680.     public void removeMouseListener(ToolTipManager c){
  681.     super.removeMouseListener(c);
  682.     }
  683.  
  684.   }
  685.  
  686.   // MEDIUM
  687.   class PanelPopup extends Panel implements Popup {
  688.     public PanelPopup(JComponent t, Dimension s) {
  689.       super();
  690.       setLayout(new BorderLayout());
  691.       add(t, BorderLayout.CENTER);
  692.       setSize(s);
  693.     }
  694.  
  695.     public Rectangle getBounds(){
  696.     return super.getBounds();
  697.     }
  698.  
  699.     public void show(JComponent invoker, int x, int y) {
  700.     Point p = new Point(x,y);
  701.     SwingUtilities.convertPointFromScreen(p,invoker.getRootPane().getLayeredPane());
  702.     invoker.getRootPane().getLayeredPane().add(this,JLayeredPane.POPUP_LAYER,0);
  703.     // 4144271
  704.     this.setBounds(p.x,p.y,getSize().width, getSize().height);
  705.     }
  706.  
  707.  
  708.     public void hide() {
  709.       Container parent = getParent();
  710.       Rectangle r = this.getBounds();
  711.       if(parent != null){
  712.     parent.remove(this);
  713.     parent.repaint(r.x,r.y,r.width,r.height);
  714.       }
  715.     }
  716.  
  717.     public void addMouseListener(ToolTipManager c){
  718.     super.addMouseListener(c);
  719.     }
  720.  
  721.     public void removeMouseListener(ToolTipManager c){
  722.     super.removeMouseListener(c);
  723.     }
  724.   }
  725.  
  726.   class WindowPopup extends Window implements Popup  {
  727.     boolean  firstShow = true;
  728.     JComponent tip;
  729.     Frame frame;
  730.  
  731.     public WindowPopup(Frame f,JComponent t, Dimension size) {
  732.       super(f);
  733.       this.tip = t;
  734.       this.frame = f;
  735.       add(t, BorderLayout.CENTER);
  736.       pack();
  737.       // setSize(size);
  738.     }
  739.  
  740.     public Rectangle getBounds(){
  741.     return super.getBounds();
  742.     }
  743.  
  744.     public void show(JComponent invoker, int x, int y) {
  745.       this.setLocation(x,y);
  746.       this.setVisible(true);
  747.  
  748.       /** This hack is to workaround a bug on Solaris where the windows does not really show
  749.        *  the first time
  750.        *  It causes a side effect of MS JVM reporting IllegalArumentException: null source
  751.        *  fairly frequently - also happens if you use HeavyWeight JPopup, ie JComboBox 
  752.        */
  753.       if(firstShow) {
  754.     this.hide();
  755.     this.setVisible(true);
  756.     firstShow = false;
  757.       }
  758.     }
  759.         
  760.     public void hide() {
  761.       super.hide();
  762.       /** We need to call removeNotify() here because hide() does something only if
  763.        *  Component.visible is true. When the app frame is miniaturized, the parent 
  764.        *  frame of this frame is invisible, causing AWT to believe that this frame
  765.        *  is invisible and causing hide() to do nothing
  766.        */
  767.       removeNotify();
  768.     }
  769.  
  770.     public void addMouseListener(ToolTipManager c){
  771.     super.addMouseListener(c);
  772.     }
  773.  
  774.     public void removeMouseListener(ToolTipManager c){
  775.     super.removeMouseListener(c);
  776.     }
  777.  
  778.   }
  779.  
  780. }
  781.